using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using AutoMapper;
using AiPlatformAdmin.Api.Data;
using AiPlatformAdmin.Api.Models;
using AiPlatformAdmin.Api.Services;
using AiPlatformAdmin.Api.DTOs;

namespace AiPlatformAdmin.Api.Controllers;

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
    private readonly AppDbContext _context;
    private readonly DocumentProcessingService _documentService;
    private readonly ILogger<DocumentsController> _logger;
    private readonly IMapper _mapper;

    public DocumentsController(
        AppDbContext context,
        DocumentProcessingService documentService,
        ILogger<DocumentsController> logger,
        IMapper mapper)
    {
        _context = context;
        _documentService = documentService;
        _logger = logger;
        _mapper = mapper;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<DocumentDto>>> GetDocuments(
        [FromQuery] int? knowledgeBaseId = null,
        [FromQuery] int skip = 0,
        [FromQuery] int limit = 20)
    {
        var query = _context.Documents.AsQueryable();

        if (knowledgeBaseId.HasValue)
        {
            query = query.Where(d => d.KnowledgeBaseId == knowledgeBaseId.Value);
        }

        var documents = await query
            .OrderByDescending(d => d.UploadedAt)
            .Skip(skip)
            .Take(limit)
            .ToListAsync();

        return Ok(_mapper.Map<IEnumerable<DocumentDto>>(documents));
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<DocumentDto>> GetDocument(int id)
    {
        var document = await _context.Documents.FindAsync(id);

        if (document == null)
        {
            return NotFound();
        }

        return Ok(_mapper.Map<DocumentDto>(document));
    }

    [HttpPost]
    public async Task<ActionResult<DocumentDto>> UploadDocument(
        [FromForm] IFormFile file,
        [FromForm] int knowledge_base_id,
        [FromForm] string chunking_mode = "fixed",
        [FromForm] int? chunk_size = null,
        [FromForm] int? chunk_overlap = null)
    {
        if (file == null || file.Length == 0)
        {
            return BadRequest("File is required");
        }

        var validModes = new[] { "fixed", "semantic", "paragraph", "none" };
        if (!validModes.Contains(chunking_mode.ToLower()))
        {
            return BadRequest("Invalid chunking mode");
        }

        if (chunking_mode.ToLower() == "fixed")
        {
            if (!chunk_size.HasValue || chunk_size.Value < 100 || chunk_size.Value > 10000)
            {
                return BadRequest("Chunk size must be between 100 and 10000 for fixed mode");
            }

            if (!chunk_overlap.HasValue || chunk_overlap.Value < 0 || chunk_overlap.Value > 1000)
            {
                return BadRequest("Chunk overlap must be between 0 and 1000 for fixed mode");
            }
        }

        try
        {
            using var stream = file.OpenReadStream();
            var document = await _documentService.ProcessDocumentAsync(
                knowledge_base_id,
                file.FileName,
                stream,
                chunking_mode,
                chunk_size,
                chunk_overlap,
                file.ContentType);

            return CreatedAtAction(nameof(GetDocument), new { id = document.Id }, _mapper.Map<DocumentDto>(document));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing document");
            return StatusCode(500, new { message = "Error processing document", error = ex.Message });
        }
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> UpdateDocument(int id, UpdateDocumentDto dto)
    {
        var document = await _context.Documents.FindAsync(id);
        if (document == null)
        {
            return NotFound();
        }

        _mapper.Map(dto, document);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteDocument(int id)
    {
        var document = await _context.Documents.FindAsync(id);
        if (document == null)
        {
            return NotFound();
        }

        try
        {
            await _documentService.DeleteDocumentAsync(document.Id);
            return NoContent();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error deleting document {Id}", id);
            return StatusCode(500, new { message = "Error deleting document", error = ex.Message });
        }
    }
}
